{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qanewqOpUw9m"
   },
   "source": [
    "# АНАЛИЗ ДАННЫХ И МАШИННОЕ ОБУЧЕНИЕ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Данные наделяют нас знаниями. Независимо от того, проводите ли вы опрос для измерения удовлетворенности клиентов или проводите химический эксперимент, вы хотите что-то получить из собранных данных.\n",
    "\n",
    "Данные могут быть неправильно поняты или неверно истолкованы. Тем не менее анализ данных позволяет сгенерировать надежные знания. У разных ученых разные подходы к анализу данных, зачастую это зависит от характера исследований и объема имеющихся данных. В течение следующих занятий мы научимся собирать, обрабатывать, исследовать и обобщать данные, а также строить различные модели для решения разнообразных задач."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вся работа будет происходить в интерактивных ноутбуках (.ipynb), которые вы можете запускать как в [Юпитере](https://practicum.yandex.ru/blog/chto-takoe-jupyter-notebook/), так и в облачной платформе [Google Colaboratory](https://colab.research.google.com/notebooks/intro.ipynb?hl=ru%20here)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python — это один из самых распространённых языков программирования. Хотя стандартные возможности Python достаточно скромны, существует огромное количество пакетов, которые позволяют решать с помощью этого языка самые разные задачи. Пожалуй, именно поэтому Python и пользуется такой популярностью среди программистов. \n",
    "\n",
    "Для решения задач анализа данных и машинного обучения мы будем (в основном) пользоваться следующими библиотеками:\n",
    "   1. `NumPy` — это один из самых широко используемых Python-пакетов. Название пакета, NumPy, расшифровывается как Numerical Python. Здесь реализовано множество вычислительных механизмов, пакет поддерживает специализированные структуры данных, в том числе — одномерные и многомерные массивы, значительно расширяющие возможности Python по выполнению различных вычислений.\n",
    "   2. Пакет `SciPy` построен на основе NumPy, в нём используются и некоторые другие вспомогательные пакеты. Он широко используется для выполнения статистических расчётов. \n",
    "   3. `Pandas` — это, после NumPy, второй по известности Python-пакет, используемый в Data Science. Его применяют в самых разных местах, например, в сферах статистики, финансов, экономики, анализа данных. Пакет Pandas часто используют для обработки больших объёмов данных. Фактически, для проведения DS-вычислений обычно используются все три пакета — Pandas, NumPy и SciPy.\n",
    "   4. `Matplotlib` — это известнейший Python-пакет для визуализации данных. Его, пожалуй, можно включить в набор основных пакетов, которые нужно освоить тому, кто пользуется Python в сфере Data Science. Он поддерживает множество стандартных средств для визуализации данных, представленных различными графиками и диаграммами.\n",
    "   5. `Scikit-Learn` — это Python-пакет для машинного обучения. Он включает в себя практически всё, что нужно дата-cатанисту (это не ошибка :))."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `Pandas`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3Mo-ZxxL_9e7"
   },
   "source": [
    "Библиотека Pandas - важная библиотека, с которой мы начнем знакомство и будем активно работать в этом учебном модуле. Pandas $-$ это модуль для первичной работы с данными, с помощью которого можно проводить простой анализ данных и предобработку данных.\n",
    "Основные возможности:\n",
    "* удобное чтение и запись данных из csv, txt, xls, SQL databases, HDF5\n",
    "* удобная работа с пропусками в данных\n",
    "* поиск, сортировка, выборка объектов, удовлетворяющих заданным критериям\n",
    "* возможности по соединению датасетов\n",
    "* красивая визуализация\n",
    "\n",
    "Импорт библиотеки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XrNOtyBlUw9o"
   },
   "outputs": [],
   "source": [
    "# Данная конструкция подключает модуль pandas и позволяет обращаться \n",
    "# к его функциям через имя pd (при желании вы можете использовать и другое короткое имя, но pd - общеупотребимое).\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "6nT_wz8i_9e-"
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "42daJft5Uw9q"
   },
   "source": [
    "## 1. Создание объекта"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "nGNGKRlwXr47"
   },
   "source": [
    "Основу <b>Pandas</b> составляют такие структуры данных, как <b>Series и DataFrame</b>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "27fn82ZXUw9r"
   },
   "source": [
    "Подробнее см. [Введение в структуры данных pandas](https://pandas.pydata.org/pandas-docs/stable/user_guide/dsintro.html#dsintro)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UHgsZTGiUw9s"
   },
   "source": [
    "<b>Series</b> - это <b>одномерный массив</b>, имеющий специальные <b>метки (индексы)</b> и способные хранить данные <b>любого</b> типа. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "exi0FDQZXwDv"
   },
   "source": [
    "![pandas-series-cummin-image-1.svg]()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "LU54d7_rUw9s",
    "outputId": "9b28fa3b-e707-42f3-c6e9-5a9724479e97"
   },
   "outputs": [],
   "source": [
    "s = pd.Series([1, 3, 5, np.nan, 6, 8])\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В строковом представлении Series, отображаемом в интерактивном режиме, индекс находится слева, а значения справа. Поскольку мы не задали индекс для данных, то по умолчанию индекс задается как `range(n)`. \n",
    "\n",
    "Получить информацию о содержании и индексировании массива можно с помощью аттрибутов `values` и `index` соответственно:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(s.values)\n",
    "print(s.index)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтобы создать объект Series с индексом, индентифицирующим каждый элемент данных в соответсвии с некоторым смыслом, можно использовать в индексе  метки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "obj1=pd.Series([25,15,20,20], index=['left','right', 'top','bottom'])\n",
    "obj1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "KusIkV7VUw9t"
   },
   "source": [
    "<b>DataFrame</b> - это <b>двумерный массив (матрица, таблица)</b>, имеющий <b>специальные метки (индексы)</b>, который хранит в своих столбцах данные <b>разных типов</b>. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-je7baEJX_Zt"
   },
   "source": [
    "![dataframe.png]()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Создание DataFrame внутренними средствами Python\n",
    "Создаем DataFrame из словаря:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict={'state':['Ohio','Ohio','Ohio','Nevada', 'Nevada','Nevada'], \n",
    "          'year':[2000, 2001, 2002, 2001, 2002, 2003],\n",
    "          'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]} # словарь, все значения которого - списки\n",
    "df=pd.DataFrame(my_dict) # создание объекта DataFrame из словаря. Ключи становятся столбцами\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Создадим датафрейм с временными метками в качестве индекса и заполним его случайными значениями"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "oaWr3b-GUw9u",
    "outputId": "12a142fc-5e5c-4fec-947f-bab2c96bbeab"
   },
   "outputs": [],
   "source": [
    "# указываем начало временнОго периода и число повторений (дни по умолчанию)\n",
    "dates = pd.date_range('20130101', periods=6) \n",
    "dates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "g_KewkvqUw9u",
    "outputId": "fffaaaf5-0f36-4d0b-965b-201cd7f7455c"
   },
   "outputs": [],
   "source": [
    "df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Или так"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "OIXduXEVUw9v",
    "outputId": "c9ca9f46-e9f1-47ae-e8ef-f57094d50de1"
   },
   "outputs": [],
   "source": [
    "df2 = pd.DataFrame({'A': 1.,\n",
    "                    'B': pd.Timestamp('20130102'), # временнАя метка\n",
    "                    'C': pd.Series(1, index=list(range(4)), dtype='float32'), # Серия на основе списка\n",
    "                    'D': np.array([3] * 4, dtype='int32'), # массив целых чисел NumPy \n",
    "                    'E': pd.Categorical([\"test\", \"train\", \"test\", \"train\"]), # категории\n",
    "                    'F': 'foo'})\n",
    "df2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "n69UvwXLUw9w"
   },
   "source": [
    "Столбцы итогового [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) имеют разные [типы данных](https://pandas.pydata.org/pandas-docs/stable/user_guide/basics.html#basics-dtypes), в зависимости от того, что за данные хранятся в столбце."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "bslxc3b0Uw9w",
    "outputId": "5ea88c34-9575-4940-f804-4414fa7cfa4e"
   },
   "outputs": [],
   "source": [
    "df2.dtypes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fECug8yLUw9x"
   },
   "source": [
    "Если вы используете `IPython` или `Jupyter (Lab) Notebook (Colab)`, то по нажатию TAB после точки отобразятся публичные атрибуты объекта (в данном случае `DataFrame`): "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "0Mh-IdY7Uw9x"
   },
   "outputs": [],
   "source": [
    "# Попробуйте убрать комментарий и нажать TAB\n",
    "df2."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YszD31Jn_9fH"
   },
   "source": [
    "## 2. Загрузка данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Зачастую данные уже хранятся в каком-нибудь файле и нам нужно только их считать для работы."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "xHTNgLVJ_9fJ"
   },
   "source": [
    "__Наиболее популярные форматы данных (при скачивании датасета из интернета)__:\n",
    "* _csv_ (comma separated file), _tsv_ (tab separated file) - таблицы, записанные в текстовые файлы с простой структурой. Эти файлы можно открывать в обычном текстовом редакторе. Pandas позволяет считывать эти данные именно в формате таблицы.\n",
    "* _xls_ (eXceL Spreadsheet $-$ таблицы Microsoft)\n",
    "* _json_ (JavaScript Object Notation, используется для _сериализации_ структур языка, то есть сохранения сложных объектов, например, вложенных списков или словарей python). Json-текст представляет собой либо набор пар ключ: значение, либо упорядоченный набор значений\n",
    "* _txt_ в иной специфичной для задачи форме (например, vowpal-wabbit и uci bag-of-words для <<мешка слов>>)\n",
    "\n",
    "В pandas есть функции для считывания во всех этих форматах.\n",
    "\n",
    "В реальной жизни данные хранятся в базах данных, откуда с помощью sql-подобных языков из них составляют файлы в указанных выше форматах.\n",
    "\n",
    "__Чтение из csv с помощью pandas__:\n",
    "[pandas.read_csv()](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html)\n",
    "У функции несколько параметров, основные необходимые:\n",
    "* filepath_or_buffer (перый и единственный обязательный аргумент) --- имя файла\n",
    "* sep $-$ разделитель (; , \\t ...)\n",
    "* quotechar $-$ символ кавычек, все что внутри считается за строку (разделители также могут входить в эту строку; ' \" ...)\n",
    "* names $-$ список названий колонок\n",
    "* header $-$ номер строки файла (с 0), которую нужно считать заголовком\n",
    "* dtype $-$ словарь, сопоставляющий именам колонок типы данных в них\n",
    "* na_values $-$ строка/список/словарь (ключи $-$ названия колонок) строковых значений, которые нужно считать пропуском.\n",
    "\n",
    "По умолчанию names=None и header=0, то есть названия колонок берутся из первой строки файла. Можно передать названия через names. Если вы не хотите давать названия, укажите header=None, тогда названия будут даны автоматически индексами с 0. Учтите, что названия нужны при дальнейшей работе с данными (если вы только не собираетесь взять оттуда только numpy-матрицу; в этом случае они не понадобятся). Следите за длиной списка названий, он должен совпадать с реальным числом колонок в файле! Чтобы заменить заголовки, записанные в файле, нужно установить header=0 и передать names.\n",
    "\n",
    "В функцию pd.read\\_csv можно передавать как путь к файлу, хранящемуся на компьютере, так и ссылку на файл в Интернете.\n",
    "\n",
    "Для чтения xls: [pandas.read_excel](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html)\n",
    "\n",
    "Для чтения sql: [pandas.read_sql](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_sql.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zn_DN8dz_9fK"
   },
   "source": [
    "Считывание данных:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "t3tJShiu_9fL"
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv(\"titanic.csv\", sep=\";\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Q8paoWJ6_9fL"
   },
   "source": [
    "Мы будем работать с данными [Titanic](https://www.kaggle.com/c/titanic): он содержит информацию о пассажирах корабля, включая их демографические характеристики и выжил пассажир или нет."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "IDl2j1wN_9fL",
    "outputId": "b679306e-84e1-4ad7-cd88-1218092e24a8"
   },
   "outputs": [],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kcLKu3-o_9fM"
   },
   "source": [
    "Каждая строчка набора данных содержит следующие поля:\n",
    "\n",
    "- `PassengerId` — номер пассажира;\n",
    "\n",
    "- `Survived` — выжил данный пассажир или нет (0 для умерших, 1 для выживших);\n",
    "\n",
    "- `Pclass` — класс пассажира (1 — высший, 2 — средний, 3 — низший);\n",
    "\n",
    "- `Name` — имя;\n",
    "\n",
    "- `Sex` — пол;\n",
    "\n",
    "- `Age` — возраст;\n",
    "\n",
    "- `SibSp` — количество братьев, сестер, сводных братьев, сводных сестер, супругов на борту титаника;\n",
    "\n",
    "- `Parch` — количество родителей, детей (в том числе приемных) на борту титаника;\n",
    "\n",
    "- `Ticket` — номер билета;\n",
    "\n",
    "- `Fare` — плата за проезд;\n",
    "\n",
    "- `Cabin` — каюта;\n",
    "\n",
    "- `Embarked` — порт посадки (C — Шербур; Q — Квинстаун; S — Саутгемптон)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yxcgD5dmUw9x"
   },
   "source": [
    "## 3. Просмотр данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "v_J_j-dfUw9x"
   },
   "source": [
    "Подробнее см. [Документацию по базовой функциональности](https://pandas.pydata.org/pandas-docs/stable/user_guide/basics.html#basics)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "f6Vw52qrUw9y"
   },
   "source": [
    "Просмотрим верхние и нижние строки полученного кадра данных:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "08VMT3-DUw9y",
    "outputId": "eb2fcdbe-1995-4436-87c6-3ed418aee06c"
   },
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "6OQ5oOpMUw9y",
    "outputId": "d0567ed7-28fb-481c-e646-24eaf44969fe"
   },
   "outputs": [],
   "source": [
    "df.tail(3) # вывести последние три строки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ROUrOoyB_9fP"
   },
   "source": [
    "Посмотреть размер таблички (число наблюдений X число признаков)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "624b6abu_9fP",
    "outputId": "932bbc59-ecb7-4164-d50a-4cfce74db79b"
   },
   "outputs": [],
   "source": [
    "df.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "WUuZP6bt_9fP",
    "outputId": "de2521cd-bb34-4270-aa70-ab8d6fc5120d"
   },
   "outputs": [],
   "source": [
    "type(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Краткое описание таблицы можно вывести так:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9Hj49XU5Uw91"
   },
   "source": [
    "Сортировка по столбцам, см. [`sort_index()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_index.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "RAoIl-yYUw91",
    "outputId": "b25a2fda-9448-447b-dd85-76e8a4a4ef6b"
   },
   "outputs": [],
   "source": [
    "df.sort_index(axis=1, ascending=False) # по умолчанию axis=0, т.е. сортировка по строкам"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LGjtWcA0Uw92"
   },
   "source": [
    "Сортировка по значениям, см. [`sort_values()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_values.html#pandas.DataFrame.sort_values):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "VIdHurGwUw92",
    "outputId": "cab39f5b-fabb-4797-c51e-24b3fa752be9"
   },
   "outputs": [],
   "source": [
    "df.sort_values(by='Survived') # по умолчанию сортировка по индексу, выбрали столбец 'Survived'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Z-JMG3K_Uw92"
   },
   "source": [
    "## 4. Работа со строками и столбцами датафрейма"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SGlPgSVk_9fT"
   },
   "source": [
    "Датафрейм - это таблица. Названия строк:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "utdXwvwc_9fT",
    "outputId": "d162b856-b8bd-4f53-ef48-085f531159fd"
   },
   "outputs": [],
   "source": [
    "# Важно, потому что иногда полезно в качестве названий строк выбрать какой-то столбец таблицы\n",
    "df.index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ND8LyzmP_9fT"
   },
   "source": [
    "Названия столбцов:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "w8BLhSZH_9fT",
    "outputId": "92d033c6-c7dd-4482-fc60-ba62cce9cfdb"
   },
   "outputs": [],
   "source": [
    "df.columns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IudtNRUYUw-I"
   },
   "source": [
    "Выбор столбца, который возвращает [`Series`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series), эквивалентно `df.A`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "y0wDpDOOUw-J",
    "outputId": "d8ea7e4c-e3fe-44b0-f275-409dc5a25283"
   },
   "outputs": [],
   "source": [
    "df['Sex']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "qTkanUpE_9fU",
    "outputId": "e738909f-ecdc-46fd-9497-274113838e30"
   },
   "outputs": [],
   "source": [
    "df.Sex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтобы извлечь несколько столбцов, нужно в квадратных скобках `[]` передать **список** названий столбцов:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "Paz7nVPG_9fU",
    "outputId": "deb29a50-8f43-4579-c143-3163ec5ee8ca"
   },
   "outputs": [],
   "source": [
    "df[[\"Age\", \"Sex\", \"Cabin\"]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "cpVqhr_4_9fU",
    "outputId": "25f010c4-d93f-40db-8731-384b84908937"
   },
   "outputs": [],
   "source": [
    "print(df.columns[0])\n",
    "print(df.dtypes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Jc1iTkKc_9fU"
   },
   "source": [
    "В машинном обучении библиотеку удобно использовать со следующей интерпретацией: по строкам датафрейма находятся объекты, по столбцам - признаки и целевая переменная. В нашем датафрейме целевая переменная задана в столбце `Survived`. Если мы бы хотели выделить часть датафрейма без этого столбца, мы бы использовали такой код:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "0BhE6MaW_9fU",
    "outputId": "1e37cb7f-d4d6-4836-dfdb-971304de85e6"
   },
   "outputs": [],
   "source": [
    "# axis указываем, потому что так требует pandas\n",
    "df.drop(\"Survived\", axis = 1).head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1Kv3JQeQ_9fV"
   },
   "source": [
    "Обратите внимание, что столбец не удалился из датафрейма навсегда. Наоборот, результат нашей операции записан в выводе, и если бы мы хотели его сохранить, мы должны были бы присвоить результат операции новой переменной."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5XUo-bLsUw-J"
   },
   "source": [
    "Доступ к **строкам** по индексу, т. е. выбор с помощью `[ ]` вырезает строки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "knLqYmtlUw-J",
    "outputId": "0a858f20-0089-4587-9823-96096081b0eb"
   },
   "outputs": [],
   "source": [
    "df[0:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Обратиться к отдельному элементу или сделать срез данных** можно с помощью методов `loc` и `iloc`. Они позволяют выбрать подмножество строк и столбцов, используя либо метки строк (`loc`), либо целые числа (`iloc`).\n",
    "[Подробнее о различиях между loc и iloc](https://towardsdatascience.com/how-to-use-loc-and-iloc-for-selecting-data-in-pandas-bd09cb4c3d79#:~:text=The%20main%20distinction%20between%20loc,0%2Dbased%20integer%20position)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9535tRMe_9fV"
   },
   "source": [
    "### Выбор по метке"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "dQfEBIdb_9fV",
    "outputId": "436a85b1-7f90-4ac0-8295-ea9a0df20595"
   },
   "outputs": [],
   "source": [
    "# Если передавать индексы как названия\n",
    "df.loc[:3, 'Name']  # метка строки, метки столбцов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "s-Ub3TuZUw-L"
   },
   "source": [
    "Выбор по нескольким осям:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "cKdNBm2WUw-L",
    "outputId": "e79f00af-3f09-4021-c1f4-e2f724320e4d"
   },
   "outputs": [],
   "source": [
    "df.loc[:, ['Name', 'Ticket']]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qOXchL9rUw-P"
   },
   "source": [
    "### Выбор по позиции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "grZSqXllUw-Q"
   },
   "source": [
    "Выбор позиции с помощью целых чисел:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "UtPj-Q69Uw-Q",
    "outputId": "07a7aa95-4568-4b7b-c819-da6e66470664"
   },
   "outputs": [],
   "source": [
    "df.iloc[3] "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Os6-dRg8Uw-R"
   },
   "source": [
    "По целочисленным срезам, действующим аналогично NumPy / Python, т.е. правое граничное значение не включается:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "28Q-vv_oUw-R",
    "outputId": "98e28f9e-32cd-4ed9-f613-4ed968303da4"
   },
   "outputs": [],
   "source": [
    "df.iloc[3:5, 0:2]  # номера строк, номер столбца"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AHCvDoDuUw-S"
   },
   "source": [
    "По спискам целочисленных позиций, аналогично стилю NumPy / Python:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "sRk39LWcUw-T",
    "outputId": "6b15c0d6-b1bb-4b61-c0e1-9026efcc526d"
   },
   "outputs": [],
   "source": [
    "df.iloc[[1, 2, 4], [0, 2]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LTv5t8j4Uw-T"
   },
   "source": [
    "Для явного создания среза строк:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "UHKb19M2Uw-T",
    "outputId": "0e88c34c-acf8-4a8e-f59f-7f600c57aae4"
   },
   "outputs": [],
   "source": [
    "df.iloc[1:3, :]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Wo0Hp6KHUw-T"
   },
   "source": [
    "Для явного создания среза столбцов:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "QoOkFDisUw-U",
    "outputId": "138689f2-f1f2-4898-851d-b14034fda8bd"
   },
   "outputs": [],
   "source": [
    "df.iloc[:, 1:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "41J9EdRhUw-U"
   },
   "source": [
    "Для явного получения значений:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "cxIIyQDGUw-U",
    "outputId": "94235164-5d68-4ccc-917e-f09f5ec6a7d7"
   },
   "outputs": [],
   "source": [
    "df.iloc[2, 4]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "USG_mYTaUw-V"
   },
   "source": [
    "### Булево индексирование"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Иногда бывает нужно вывести строки с фиксированными значениями нескольких полей. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qsCg_PnKUw-V"
   },
   "source": [
    "Использование значений одного столбца для выбора данных:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "VemGGrs1Uw-V",
    "outputId": "65491944-9066-44b5-ca26-96021c3d9123"
   },
   "outputs": [],
   "source": [
    "df[df['Age'] > 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df[(df['Age'] > 0) & (df['Sex'] == 'female')]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Копирование объектов Pandas\n",
    "\n",
    "1. В Python операция присваивания создает **ссылку** на объект, стоящий справа, поэтому если после выполнения такого кода:\n",
    "\n",
    "        df1=pd.Dataframe(my_dict)\n",
    "        df2=df1\n",
    "    \n",
    "    вы решите изменить `df2`, например, то те же самые изменения произойдут и с `df1`, потому что и та, и другая переменная ссылаются на один и тот же объект.\n",
    "    \n",
    "2. При выполнениее кода\n",
    "        `object_new=object.copy(deep=True)` \n",
    "    (параметр `deep` равен `True` по умолчанию) происходит создание нового **объекта** и копирование в него индексов и содержания исходного объекта `object`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "FrhXG59gUw-Y"
   },
   "outputs": [],
   "source": [
    "df2 = df.copy() # создаем копию исходгого кадра данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Использование метода [`isin()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.isin.html#pandas.Series.isin) для фильтрации:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "zu_M6cYHUw-Z",
    "outputId": "0a39641b-1371-49b7-a135-abe0d592c921"
   },
   "outputs": [],
   "source": [
    "df2[df2['Sex'].isin(['female'])] # фильтруем"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "poP42yRWUw-c"
   },
   "source": [
    "## 5.  Отсутствующие данные"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CQn5go11Uw-c"
   },
   "source": [
    "pandas в основном использует значение [`np.nan`](https://numpy.org/doc/stable/user/misc.html) для представления отсутствующих данных. По умолчанию они не включается в вычисления, см. подробнее в [Документации](https://pandas.pydata.org/pandas-docs/stable/user_guide/missing_data.html#missing-data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SXPQQr3AUw-d"
   },
   "source": [
    "Чтобы удалить строки, в которых отсутствуют данные, см. [`dropna()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "e4qltlvAUw-d",
    "outputId": "426dc8fe-9c4d-41d4-b333-3ae3760b1e0b"
   },
   "outputs": [],
   "source": [
    "df.dropna() # how='any', axis=0 по умолчанию, т.е. удаляются все строки с пропущенными данными"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SFcgH85VUw-d"
   },
   "source": [
    "Заполнение недостающих данных:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "vLsaV7MoUw-d",
    "outputId": "59c92c65-7dc2-495b-b886-aaf09df9ee54"
   },
   "outputs": [],
   "source": [
    "df.fillna(value=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yIUSdfXeUw-d"
   },
   "source": [
    "Чтобы получить логическую маску, в которой значениями являются nan."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ZBMJ-C_pUw-e",
    "outputId": "61e17f99-c9cf-42ff-eeef-79fad2030089"
   },
   "outputs": [],
   "source": [
    "pd.isna(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "auFB6BlmUw-7"
   },
   "source": [
    "## 6. Получение и запись данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6J5ZSxLnUw-7"
   },
   "source": [
    "### CSV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "giEIa0OtUw-7"
   },
   "source": [
    "см. [про запись в csv файлы](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-store-in-csv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8o3WEXYPUw-7"
   },
   "outputs": [],
   "source": [
    "df.to_csv('df.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1ALssJkuUw-7"
   },
   "source": [
    "см. [про чтение csv файлов](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-read-csv-table)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ncc9GU0ZUw-7"
   },
   "outputs": [],
   "source": [
    "pd.read_csv('df.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IjGt0kXpUw-8"
   },
   "source": [
    "### Excel"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FxN5VvI0Uw-9"
   },
   "source": [
    "см. [про чтение и запись в MS Excel](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-excel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8jsTzMVyUw-9"
   },
   "source": [
    "Запись в excel файл:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "7H0R89jAUw-9"
   },
   "outputs": [],
   "source": [
    "df.to_excel('df.xlsx', sheet_name='Sheet1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ghcSUhP9Uw-9"
   },
   "source": [
    "Чтение из excel файла:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "Mg_k7ljwUw-9"
   },
   "outputs": [],
   "source": [
    "pd.read_excel('df.xlsx', 'Sheet1', index_col=None, na_values=['NA'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AqwPZ9IG_9fc"
   },
   "source": [
    "## 7. Анализ и преобразование датафрейма"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "FcSR04r7_9fd"
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv(\"titanic.csv\", sep=\";\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "H3ZAUeoE_9fd"
   },
   "source": [
    "Основная информация по датафрейму:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "msuMSxgI_9fd",
    "outputId": "1e921ad1-f346-4342-cad0-d3be5b27e66f"
   },
   "outputs": [],
   "source": [
    "df.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HGqFaq1q_9fd"
   },
   "source": [
    "По этим статистикам можно понять, одинаковый ли масштаб имеют признаки (например, Age измеряется от 0 до 80, а Pclass в единицах - от 1 до 3). Также можно понять, есть ли пропуски в данных (по count). Например, в графе Age есть пропуски."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-Qslr4Ry_9fd"
   },
   "source": [
    "Использовать столбец Name для задания названий строк (index):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "acnSG3zn_9fd"
   },
   "outputs": [],
   "source": [
    "df.set_index(df[\"Name\"], inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "rGL-g68o_9fd",
    "outputId": "35f97dec-8eda-4d28-f583-6a0525d97070"
   },
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "u7jZbuN2_9fe"
   },
   "source": [
    "Теперь строки индексируются с помощью Name (выделено жирным в начале каждой строки)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yWN4hyB5_9ff"
   },
   "source": [
    "Уникальные значения в столбце:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "fL-t0Cuj_9fg",
    "outputId": "94dd8009-6d51-44c7-b83c-19be1ad3a840"
   },
   "outputs": [],
   "source": [
    "set(df[\"Sex\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "H5d95z-r_9fg",
    "outputId": "82955522-296c-42c2-b8dc-501969d290b1"
   },
   "outputs": [],
   "source": [
    "df['Sex'].unique()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kgs66yaJ_9fg"
   },
   "source": [
    "Уникальные значения в столбце с числом строк с таким значением:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "GNEKbPih_9fg",
    "outputId": "a38258f4-4ce8-4a00-926a-9c4eff55db03"
   },
   "outputs": [],
   "source": [
    "df[\"Sex\"].value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VPIb1XPX_9fg"
   },
   "source": [
    "Перекодирование столбца с помощью функции map:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "GfERVdLf_9fh",
    "outputId": "2ddbfdd4-cb65-467b-f6f9-4c07436c89cb"
   },
   "outputs": [],
   "source": [
    "sex = df[\"Sex\"]\n",
    "sex.map({\"male\":1, \"female\":-1, \"unknown\":0}).head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BlUd-0Pc_9fh"
   },
   "source": [
    "Функция apply: применение функции поэлементно к столбцу или строке (+ создание нового столбца, потому что apply возвращает результат и никак не модифицирует датафрейм)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "W1bhy0dw_9fh"
   },
   "outputs": [],
   "source": [
    "def func(x):\n",
    "    return x + 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "7WK0hM4I_9fh"
   },
   "outputs": [],
   "source": [
    "df[\"NewAge\"] = df[\"Age\"].apply(lambda x: x+100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "9-mjtVV3_9fh",
    "outputId": "9c980942-d2a5-48f1-899e-2386ceee4af4"
   },
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Полезные методы (команды для массивов):\n",
    "- `.sum()` – сумма элементов;\n",
    "- `.count()` – количество появлений элемента;\n",
    "- `.mean()` – среднее элементов;\n",
    "- `.min()` – минимальный элемент;\n",
    "- `.max()` – максимальный элемент."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['Age'].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kjv_NOq9_9fi"
   },
   "source": [
    "Функция groupby: создание групп по значению какого-то столбца (или группы столбцов)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ATRLziyf_9fj",
    "outputId": "358b064c-f728-401b-e8f8-93a1a6351ef5"
   },
   "outputs": [],
   "source": [
    "df.groupby(\"Sex\")['Age'].apply(lambda x: x.mean())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "E26p-4s1_9fj"
   },
   "source": [
    "Создаем столбец с фамилией:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "jVsLHA8B_9fj"
   },
   "outputs": [],
   "source": [
    "df[\"Family\"] = df[\"Name\"].apply(lambda s: s.split(\";\")[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "nFuc1BRz_9fk",
    "outputId": "35243ecd-9819-4611-b5f9-c5e94f78646d"
   },
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "tdzwvfw3_9fl",
    "outputId": "6ca2417a-e9fc-4993-c4b2-95291f2ca422"
   },
   "outputs": [],
   "source": [
    "df.groupby(\"Family\")[\"Age\"].count().head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WorfYXnh_9fl"
   },
   "source": [
    "Сколько семей, в которых больше трех человек?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "-ZLajQFN_9fl",
    "outputId": "0401dd77-8944-4820-c12d-cd2b8b8dc78a"
   },
   "outputs": [],
   "source": [
    "(df.groupby(\"Family\")[\"Age\"].count() > 3).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kSI1bFOB_9fl"
   },
   "source": [
    "# Немного заданий, которые позволят нам \"понять\" данные"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3lbcwvOC_9fm"
   },
   "source": [
    "### Задача 1. Какова доля семей, в которых минимальный возраст меньше 20 (семьи с детьми)?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "lC76Rn_U_9fm"
   },
   "source": [
    "### Задача 2. Какова доля выживших пассажиров из класса 3? А пассажиров из класса 1?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "etS0GSlF_9fm"
   },
   "source": [
    "### Задача 3. Сколько пассажиров выжило, а сколько - нет?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1cd_sWEa_9fn"
   },
   "source": [
    "### Задача 4. Создайте столбец \"IsChild\", который равен 1, если возраст меньше 20, и 0 иначе. Для пропущенных значений поведение функции может быть произвольным."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "w_We14fm_9fo"
   },
   "source": [
    "### Задача 5. Какова доля выживших женщин из первого класса? А доля выживших мужчин из 3 класса?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Вывод: <font color='white'>  если вы небогатый мужчина, то трансатлантические переезды по воде в начале XX века вам лучше не совершать.**</font>"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [
    "9535tRMe_9fV",
    "qOXchL9rUw-P",
    "USG_mYTaUw-V",
    "6J5ZSxLnUw-7",
    "IjGt0kXpUw-8",
    "3lbcwvOC_9fm",
    "lC76Rn_U_9fm",
    "etS0GSlF_9fm",
    "1cd_sWEa_9fn",
    "w_We14fm_9fo"
   ],
   "name": "Семинар. Pandas.ipynb",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
